#include "zbComm.h"

u16 RxCounter = 0;
CircularBuffer rxUSCBuff;
u8 byteBuffer[bufferSize];
u8 rxByte = 0; // current rx byte
extern pktHdr txHdr;
extern dmaPush dmaTX;

void initComm()
{
	// init circular buffer
	cbInit(&rxUSCBuff);
  	// --- config for usart comm
	// init the dma for usart tx
	initDMA2();
	// init the usart output 
	USART2_Config();
}

void cbInit(CircularBuffer *cb) {
	cb->elems = byteBuffer;
    cb->size  = bufferSize; /* include empty elem */
    cb->start = 0;
    cb->count = 0;
}
 
int cbIsFull(CircularBuffer *cb) {
    return cb->count == cb->size; }
 
int cbIsEmpty(CircularBuffer *cb) {
    return cb->count == 0; }

int cbCount(CircularBuffer *cb) {
    return cb->count; }
 
void cbWrite(CircularBuffer *cb, u8 *elem) {
    int end = (cb->start + cb->count) % cb->size;
    cb->elems[end] = *elem;
    if (cb->count == cb->size)
        cb->start = (cb->start + 1) % cb->size; /* full, overwrite */
    else
        ++ cb->count;
}
 
void cbRead(CircularBuffer *cb, u8 *elem) {
    *elem = cb->elems[cb->start];
    cb->start = (cb->start + 1) % cb->size;
    -- cb->count;
}

/**
  * @brief 
  *       
  *         
  * @note   
  * @param  none
  * @retval none
  */
void USART2_Config(void)
{
	USART_InitTypeDef 		USART_InitStructure;
	NVIC_InitTypeDef 		NVIC_InitStructure;
	
	//Usart2_GPIO();
	GPIO_InitTypeDef GPIO_InitStructure;
	
	#ifndef STM32F10X_LD_VL
	GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);
	#endif

	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB1PeriphClockCmd( RCC_APB1Periph_USART2, ENABLE); 

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	         
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  
	GPIO_Init(GPIOA, &GPIO_InitStructure);		   

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	        
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   
	GPIO_Init(GPIOA, &GPIO_InitStructure);	
	USART_Cmd(USART2, DISABLE);

	/* Enable the USARTz Interrupt */
	NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
    USART_InitStructure.USART_BaudRate = UARTBAUD;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_Init(USART2, &USART_InitStructure);

	// enable this int to trigger dma ?
	//USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
	//USART_ITConfig(USART2, USART_IT_TXE, ENABLE);

	// setup dma for usart
	USART_DMACmd(USART2, USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE);

	// hold onto your butts
	USART_Cmd(USART2, ENABLE);
}

void USART2_IRQHandler(void)
{
	// if we get overrun 
	if(USART_GetFlagStatus(USART2, USART_FLAG_ORE) != RESET)
	{
		rxByte = USART_ReceiveData(USART2);
	}
	// if we are here because it rxne then store the data
	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
	{
			// read dr to clear all flags
			rxByte = USART_ReceiveData(USART2);
 			cbWrite(&rxUSCBuff, &rxByte);
			
			//if(cbIsFull(&rxUSCBuff))
			//{
				/* Disable the USARTy Receive interrupt */
				//USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);
				// mark buffer overflow
			//	mygVars->status |= ERR_PKT_OF;
			//}
			//USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
	}
	//USART_ClearFlag(USART2,USART_FLAG_RXNE);
}

/**
  * @brief 
  *       
  *         
  * @note   
  * @param  none
  * @retval none
  */
void initDMA2(void)
{
	NVIC_InitTypeDef 		NVIC_InitStructure;

	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

	// enable interrupt on transfer complete of dma
	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel7_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00; // ??
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;		 // ??
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);	
}

/**
  * @brief 
  *       
  *         
  * @note   
  * @param  none
  * @retval none
  */
//void DMA_RXPacket(u8 buffer[], int len)
//{
//	DMA_InitTypeDef 		DMA_InitStructure;
//
//	/* USARTy_Tx_DMA_Channel (triggered by USARTy Tx event) Config */
//	DMA_DeInit(DMA1_Channel7);
//	DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40004404;	// usart2 data register
//	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)buffer;
//	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
//	DMA_InitStructure.DMA_BufferSize = len;
//	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
//	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
//	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
//	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
//	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
//	DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
//	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
//	DMA_Init(DMA1_Channel7, &DMA_InitStructure);
//
//	mygVars->dataState = waitingfordata; // waiting for data
//
//	//DMA int on transfer complete, triggers when data has been transfered (buffersize)
//	DMA_ITConfig(DMA1_Channel7, DMA_IT_TC, ENABLE);
//
//	// start the dma transfer, it will execute now
//	DMA_Cmd(DMA1_Channel7, ENABLE);
//}

/**
  * @brief 
  *       
  *         
  * @note   
  * @param  none
  * @retval none
  */
void DMA_TXPacket(u8 packet[], int len)
{
	DMA_InitTypeDef 		DMA_InitStructure;

	/* USARTy_Tx_DMA_Channel (triggered by USARTy Tx event) Config */
	DMA_DeInit(DMA1_Channel7);
	DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40004404;	// usart2 data register
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)packet;
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
	DMA_InitStructure.DMA_BufferSize = len;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
	DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	DMA_Init(DMA1_Channel7, &DMA_InitStructure);

	mygVars->dataState = sendingdata;

	//DMA int on transfer complete, triggers when data has been transfered (buffersize)
	//DMA_ITConfig(DMA1_Channel7, DMA_IT_TC, ENABLE);
	// WE broke this with txpush, int will not work well with this anymore i dont think
	// unless we change the dmatx.state

	// start the dma transfer, it will execute now
	DMA_Cmd(DMA1_Channel7, ENABLE);
}

void DMA_TXPush(void)
{
	DMA_InitTypeDef 		DMA_InitStructure;
	u8 *dataPointer = 0;
	u16 len = 0;

	if(dmaTX.state == done)
		return;
	if(dmaTX.state == data)
	{
		dmaTX.state = done;
		dataPointer = dmaTX.offset;
		len = dmaTX.count;
	}
	if(dmaTX.state == new)
	{
		dmaTX.state = data;
		dataPointer = dmaTX.txHdr;
		len = hdrSize;
	}

	/* USARTy_Tx_DMA_Channel (triggered by USARTy Tx event) Config */
	DMA_DeInit(DMA1_Channel7);
	DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40004404;	// usart2 data register
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)dataPointer;
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
	DMA_InitStructure.DMA_BufferSize = len;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
	DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	DMA_Init(DMA1_Channel7, &DMA_InitStructure);

	//DMA int on transfer complete, triggers when data has been transfered (buffersize)
	DMA_ITConfig(DMA1_Channel7, DMA_IT_TC, ENABLE);

	// start the dma transfer, it will execute now
	DMA_Cmd(DMA1_Channel7, ENABLE);
}

/**
  * @brief 
  *       
  *         
  * @note   
  * @param  none
  * @retval none
  */
void DMA1_Channel7_IRQHandler(void)
{
	// clear the it bit
	DMA_ClearITPendingBit(DMA1_IT_GL7 | DMA1_IT_TC7);
    // kick off next segment or quit
	DMA_TXPush();


}

